<script setup lang="ts">
import { FormInfo, ChartResults } from "@/views/resourceAccess/components";
import { reactive, ref, watch } from "vue";
import { chartResults, formInfo } from "../components/interface";
import dataMock_time from "./assets/dataMock_time.json";
import { socket } from "./socket";
import CPA_CTO_MOCK from "./assets/inference/CTO_record_task0.json";
import CPA_DTO_MOCK from "./assets/inference/DTO_UX_record_task0.json";
const formProps: formInfo = reactive({
  title: "算力分配",
  btnNames: ["开始卸载", "暂停", "结束"],
  btnDisabled: [false, false, false],
  btnLoading: [false, false, false],
  formInfoList: [
    {
      id: 1,
      title: "待处理任务选择",
      inputType: "0",
      options: [
        {
          value: "0",
          label: "布匹瑕疵检测任务"
        },
        {
          value: "1",
          label: "故障状态监测任务"
        }
      ]
    },
    {
      id: 2,
      title: "配置文件",
      inputType: "1",
      options: undefined
    },
    {
      id: 3,
      title: "基准处理方法",
      inputType: "0",
      options: [
        {
          value: "CTO",
          label: "集中式决策任务卸载(CTO)"
        }
      ]
    },
    {
      id: 4,
      title: "优化算法",
      inputType: "0",
      options: [
        {
          value: "DTO-UX",
          label: "基于凸优化的决策算法DTO-UX"
        },
        {
          value: "DTO-UG",
          label: "基于贪心的决策算法DTO-UG"
        }
      ]
    }
  ]
});
const chartResultsProps: chartResults = reactive({
  header: [],
  result: "优化训练方法比基准训练方法减少平均响应时间40%",
  chartSelect: [0, 1],
  chartData: [
    {
      title: "响应时间(s)",
      legend: ["基准处理方法", "优化处理方法"],
      xAxisName: "时序",
      xAxisData: ["20", "40", "80", "100", "120", "140", "160", "180", "200"],
      yAxisData: undefined, // 一些空属性为undefined来确保编译器检测为chartData下的所有对象都能保持chartInfo类型
      seriesData: [
        {
          name: "基准处理方法",
          data: [2, 2.3, 1.6, 2.41, 2.1]
        },
        {
          name: "优化处理方法",
          data: [1.7, 1.5, 2, 1.9, 2.3]
        }
      ]
    },
    {
      title: "平均响应时间(s)",
      legend: [""],
      xAxisName: undefined,
      xAxisData: undefined,
      yAxisData: ["基准处理方法", "优化处理方法"],
      seriesData: [5.9, 3.5]
    }
  ]
});

const initStaticChart = (dataStatic1, dataStatic2) => {
  const xData = [],
    basicSeriesData = [],
    optSeriesData = [];
  let avgTimeBasic = 0,
    avgTimeOpt = 0;
  for (let i = 0; i < 50; i++) {
    xData.push(dataStatic1[i].epoch);
    basicSeriesData.push(Number(dataStatic1[i].response_time));
    avgTimeBasic = Number(dataStatic1[i].avg_response_time);
    optSeriesData.push(Number(dataStatic2[i].response_time));
    avgTimeOpt = Number(dataStatic2[i].avg_response_time);
  }
  // dataStatic1.forEach(item => {
  //   xData.push(item.epoch);
  //   basicSeriesData.push(Number(item.response_time));
  //   avgTimeBasic = Number(item.avg_response_time);
  // });
  // dataStatic2.forEach(item => {
  //   optSeriesData.push(Number(item.response_time));
  //   avgTimeOpt = Number(item.avg_response_time);
  // });
  const save = (((avgTimeBasic - avgTimeOpt) / avgTimeBasic) * 100).toFixed(2);

  chartResultsProps.chartData[0].xAxisData = xData;
  chartResultsProps.chartData[0].seriesData[0]["data"] = basicSeriesData;
  chartResultsProps.chartData[0].seriesData[1]["data"] = optSeriesData;
  chartResultsProps.chartData[1].seriesData[0] = avgTimeBasic;
  chartResultsProps.chartData[1].seriesData[1] = avgTimeOpt;
  chartResultsProps.result = `优化训练方法比基准训练方法减少平均响应时间${save}%`;
};
initStaticChart(CPA_CTO_MOCK, CPA_DTO_MOCK);

// 是否仿真
let mock = false;
let waitTime = 1000;
const mockBasicStop = ref(false),
  mockOptStop = ref(false);
let basicRendering = false,
  optRendering = false;
//变量
let chartResBasic = [],
  chartResOpt = [],
  xAData = [];
let hasStart = false;
const receiveData = ref(false);
// 多次暂停标志
let basicShouldStop = false,
  optShouldStop = false;
let basicTimer1 = null,
  basicTimer2 = null,
  optTimer1 = null,
  optTimer2 = null;
const hasPauseBasic = ref(false),
  hasPauseOpt = ref(false),
  hasStop = ref(false);
const renderNumBasic = ref(-1),
  renderNumOpt = ref(-1);
const pause = ref(false);
const sleep = (ms: number) => {
  return new Promise(resolve => setTimeout(resolve, ms));
};

// 开始渲染
const startRender = async () => {
  basicShouldStop = false;
  optShouldStop = false;
  // 需要判断当前数据是否为最新
  // 若为旧数据
  // 计算当前渲染距离下一次渲染需要多少时间
  // 如果连续快速点击暂停按钮则会导致渲染错误，但是正常的操作也不会点这么快吧。。。。或者加条件限制不能这么快点击，起码等到下一次渲染完成后才能点击
  basicTimer1 = setTimeout(async () => {
    while (
      renderNumBasic.value < chartResBasic.length - 1 &&
      !basicShouldStop
    ) {
      let bTime =
        chartResBasic[renderNumBasic.value + 1].response_time * waitTime;
      basicTimer2 = setTimeout(() => {
        basicRendering = true;
        renderNumBasic.value++;
        renderChart(chartResBasic, 0, renderNumBasic.value);
        basicRendering = false;
      }, bTime);
      await sleep(bTime);
      // 如果更新到最新数据，则继续执行监听端口的数据
      console.log("isStartBasic1", renderNumBasic.value, chartResBasic.length - 1, chartResBasic.length);
      if (renderNumBasic.value == chartResBasic.length - 1) {
        hasPauseBasic.value = false;
      }
    }
  }, 500);
  optTimer1 = setTimeout(async () => {
    while (renderNumOpt.value < chartResOpt.length - 1 && !optShouldStop) {
      let oTime = chartResOpt[renderNumOpt.value + 1].response_time * waitTime;
      optTimer2 = setTimeout(() => {
        optRendering = true;
        renderNumOpt.value++;
        renderChart(chartResOpt, 1, renderNumOpt.value);
        optRendering = false;
      }, oTime);
      await sleep(oTime);
      console.log("isStartOpt1", renderNumOpt.value, chartResOpt.length - 1, chartResOpt.length);

      if (renderNumOpt.value == chartResOpt.length - 1) {
        hasPauseOpt.value = false;
      }
    }
  }, 500);
};
// 暂停渲染
const pauseRender = async () => {
  clearTimeout(basicTimer1);
  clearTimeout(basicTimer2);
  clearTimeout(optTimer1);
  clearTimeout(optTimer2);
  basicShouldStop = true;
  optShouldStop = true;
  renderResult();
};

// 终止渲染
const stopRender = () => {
  hasStart = false;
  pauseRender();
};
const stopSocket = () => {
  socket.off("computing_power_allocate_intermediate_result");
  socket.off("computing_power_allocate_end_train_confirm");
};
// 渲染表格
const renderChart = (dataArr: any, flag: number, curNum: number) => {
  // flag:0-basic,flag:1-opt,
  if (xAData[curNum] == undefined) {
    console.log(dataArr, flag, xAData, curNum);
  }
  if (!chartResultsProps.chartData[0].xAxisData.includes(xAData[curNum])) {
    chartResultsProps.chartData[0].xAxisData.push(xAData[curNum]);
  }
  chartResultsProps.chartData[0].seriesData[flag]["data"].push(
    dataArr[curNum].response_time
  );
  chartResultsProps.chartData[1].seriesData[flag] =
    dataArr[curNum].avg_response_time;
};
// 渲染结果
const renderResult = () => {
  if (chartResBasic.length != 0 && chartResOpt.length != 0) {
    const minEpoch =
      renderNumBasic.value > renderNumOpt.value
        ? renderNumOpt.value
        : renderNumBasic.value;
    console.log(renderNumBasic.value, renderNumOpt.value, minEpoch);
    const avgBasic = chartResBasic[minEpoch].avg_response_time,
      avgOpt = chartResOpt[minEpoch].avg_response_time;
    const save = (((avgBasic - avgOpt) / avgBasic) * 100).toFixed(2);
    chartResultsProps.result = `优化训练方法比基准训练方法减少平均响应时间${save}%`;
  }
};

// 初始化数据
const initChartData = () => {
  chartResultsProps.chartData[0].xAxisData = [];
  chartResultsProps.chartData[0].seriesData[0]["data"] = [];
  chartResultsProps.chartData[0].seriesData[1]["data"] = [];
  chartResultsProps.chartData[1].seriesData = [0, 0];
  chartResultsProps.result = "";
  chartResBasic = [];
  chartResOpt = [];
  xAData = [];
  hasStart = false;
  basicShouldStop = false;
  optShouldStop = false;
  basicTimer1 = null;
  basicTimer2 = null;
  optTimer1 = null;
  optTimer2 = null;
  receiveData.value = false;
  hasPauseBasic.value = false;
  hasPauseOpt.value = false;
  hasStop.value = false;
  renderNumBasic.value = -1;
  renderNumOpt.value = -1;
  pause.value = false;
};
const initMockData = () => {
  mockBasicStop.value = false;
  mockOptStop.value = false;
  basicRendering = false;
  optRendering = false;
};
// 开始时的按钮状态
const startBtnStatus1 = () => {
  formProps.btnDisabled[1] = true;
  formProps.btnDisabled[2] = true;
};
const startBtnStatus2 = () => {
  formProps.btnDisabled[1] = false;
  formProps.btnDisabled[2] = false;
};
// 终止时的按钮状态
const stopBtnStatus1 = () => {
  formProps.btnLoading = [false, false, true];
  formProps.btnDisabled = [true, true, false];
  formProps.btnNames[2] = "结束中...";
};
const stopBtnStatus2 = () => {
  formProps.btnLoading = [false, false, false];
  formProps.btnDisabled = [false, false, false];
  formProps.btnNames = ["开始卸载", "暂停", "结束"];
};
const btnClick1 = async e => {
  initChartData();
  startBtnStatus1();
  hasStart = true;
  if (mock) {
    initMockData();
    const mock_length = CPA_CTO_MOCK.length;
    setTimeout(async () => {
      for (let i = 0; i < mock_length; i++) {
        const data = CPA_CTO_MOCK[i];
        await sleep(Number(data["response_time"]) * waitTime);
        if (!hasStart) break;
        // 判断是否存在最新的epoch
        if (!xAData.includes(data["epoch"])) {
          xAData.push(data["epoch"]);
        }
        let res = {
          epoch: data["epoch"],
          response_time: Number(data["response_time"]),
          avg_response_time: Number(data["avg_response_time"])
        };
        console.log(res);

        chartResBasic.push(res);
        if (!hasPauseBasic.value && !basicShouldStop) {
          renderNumBasic.value++;
          renderChart(chartResBasic, 0, renderNumBasic.value);
        }
        if (i == mock_length - 1) {
          mockBasicStop.value = true;
        }
      }
    }, 500);
    setTimeout(async () => {
      for (let i = 0; i < mock_length; i++) {
        const data = CPA_DTO_MOCK[i];
        await sleep(Number(data["response_time"]) * waitTime);
        if (!hasStart) break;
        // 判断是否存在最新的epoch
        if (!xAData.includes(data["epoch"])) {
          xAData.push(data["epoch"]);
        }
        let res = {
          epoch: data["epoch"],
          response_time: Number(data["response_time"]),
          avg_response_time: Number(data["avg_response_time"])
        };
        console.log(res);
        chartResOpt.push(res);
        if (!hasPauseOpt.value && !optShouldStop) {
          renderNumOpt.value++;
          renderChart(chartResOpt, 1, renderNumOpt.value);
        }
        if (i == mock_length - 1) {
          mockOptStop.value = true;
        }
      }
    }, 500);
  } else {
    const params = {
      about: "computing_power_allocate",
      task_type: e[1][0].value,
      config: e[1][1].value,
      baseline: e[1][2].value,
      optimal: e[1][3].value
    };
    socket.on("computing_power_allocate_intermediate_result", data => {
      if (!receiveData.value) {
        startBtnStatus2();
        receiveData.value = true;
      }
      const epoch = data["epoch"].toString();
      // 判断是否存在最新的epoch
      if (!xAData.includes(epoch)) {
        xAData.push(epoch);
      }
      let res = {
        epoch: epoch,
        response_time: data["response_time"],
        avg_response_time: data["avg_response_time"]
      };
      // 渲染数据
      if (data["is_optimal"] == 0) {
        chartResBasic.push(res);
        // hasPauseBasic：发生暂停说明渲染数据与最新数据存在延迟
        // basicShouldStop：若恰巧最后一次暂停时渲染的数据与当前同步，那么下一次渲染时若未点继续则应暂停
        if (!hasPauseBasic.value && !basicShouldStop) {
          // renderNumBasic记录当前basic渲染的位置
          renderNumBasic.value++;
          renderChart(chartResBasic, 0, renderNumBasic.value);
        }
      } else if (data["is_optimal"] == 1) {
        chartResOpt.push(res);
        if (!hasPauseOpt.value && !optShouldStop) {
          renderNumOpt.value++;
          renderChart(chartResOpt, 1, renderNumOpt.value);
        }
      }
      console.log("computing_power_allocate_intermediate_result", data);
    });
    socket.on("computing_power_allocate_end_train_confirm", data => {
      // 1.不存在暂停事件则直接终止
      // 2.当前数据已更新为最新数据说明暂停造成的延迟失效，可终止
      if (!hasPauseBasic.value && !hasPauseOpt.value) {
        stopRender();
        stopSocket();
        stopBtnStatus2();
      }
      // 后端终止标志
      hasStop.value = true;
      console.log("computing_power_allocate_end_train_confirm1", data);
    });
    socket.emit("start_train", params, res => {
      console.log("training_start", params);
    });
  }
  formProps.btnLoading[0] = true;
  formProps.btnNames[0] = "卸载中...";
};

const btnClick2 = async e => {
  // 暂停状态为true，点击按钮
  // 未开始时不能够点击
  if (hasStart) {
    formProps.btnLoading[1] = true;
    // 若为暂停，则点击继续
    if (pause.value) {
      formProps.btnNames[1] = "继续中...";
      await sleep(3000);
      formProps.btnNames[1] = "暂停";
      startRender();
    } else {
      // 若为继续，则点击暂停
      formProps.btnNames[1] = "暂停中...";
      pauseRender();
      await sleep(3000);
      formProps.btnNames[1] = "继续";
    }
    formProps.btnLoading[1] = false;
    hasPauseBasic.value = true;
    hasPauseOpt.value = true;
    pause.value = !pause.value;
  }
};

const btnClick3 = async e => {
  stopBtnStatus1();
  stopRender();
  if (!mock) {
    socket.on("computing_power_allocate_end_train_confirm", data => {
      stopSocket();
      stopBtnStatus2();
      // 后端终止标志
      hasStop.value = true;
      console.log("computing_power_allocate_end_train_confirm2", data);
    });
    socket.emit(
      "end_train",
      {
        about: "computing_power_allocate",
        baseline: e[1][2].value,
        optimal: e[1][3].value
      },
      data => {
        console.log("end_train", data);
      }
    );
  }
};
watch(
  () => [hasStop.value, hasPauseBasic.value, hasPauseOpt.value],
  (newVal, oldVal) => {
    console.log("hasStop:", hasStop.value, "hasPauseBasic:", hasPauseBasic.value, "hasPauseOpt:", hasPauseOpt.value);
    console.log(newVal, oldVal);

    if (newVal[0] && !newVal[1] && !newVal[2]) {
      console.log("stop");
      stopRender();
      stopSocket();
      stopBtnStatus2();
    }
  }
);
// 暂停后的Mock操作
watch(
  () => [
    mockBasicStop.value,
    mockOptStop.value,
    hasPauseBasic.value,
    hasPauseOpt.value
  ],
  (newVal, oldVal) => {
    if (newVal[0] && newVal[1] && !newVal[2] && !newVal[3]) {
      console.log("stop");
      stopRender();
      stopBtnStatus2();
    }
  }
);
</script>

<template>
  <el-row :gutter="20">
    <el-col :span="12" style="min-height: 200px">
      <el-col style="min-height: 200">
        <FormInfo
          :title="formProps.title"
          :btnNames="formProps.btnNames"
          :btnDisabled="formProps.btnDisabled"
          :btnLoading="formProps.btnLoading"
          :formInfoList="formProps.formInfoList"
          @btnClick1="btnClick1"
          @btnClick2="btnClick2"
          @btnClick3="btnClick3"
        />
      </el-col>
    </el-col>
    <el-col :span="12" style="min-height: 200px">
      <el-col style="min-height: 200px">
        <ChartResults
          :header="chartResultsProps.header"
          :chartSelect="chartResultsProps.chartSelect"
          :chartData="chartResultsProps.chartData"
          :result="chartResultsProps.result"
        />
      </el-col>
    </el-col>
  </el-row>
</template>
<style lang="scss" scoped>
.info-container {
  height: 93.5vh;
}
</style>